﻿using AMS.Common.ToolChains;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Options;
using OA.Infrastructure.DomainModels.Message;
using OA.Infrastructure.WeCom;
using System.Net.Http.Json;
using System.Text.Encodings.Web;
using System.Text.Unicode;

namespace OA.Infrastructure.Impl;

internal class WeComService : IWeComService
{
    private readonly HttpClient _httpClient;
    private readonly WeComOptions _weComOptions;
    private readonly IMemoryCache _cache;

    public string AppEntryUrl { get; private set; }

    public WeComService(IHttpClientFactory httpClientFactory, IOptions<WeComOptions> wecomOptions, IMemoryCache cache)
    {
        _httpClient = httpClientFactory.CreateClient();
        _weComOptions = wecomOptions.Value;
        _cache = cache;

        var trustIP = Environment.GetEnvironmentVariable("TrustIP");
        AppEntryUrl = string.IsNullOrEmpty(trustIP) ? _weComOptions.RedirectUri : $"{trustIP}/ams";
    }

    public async Task<OperationalResult<string>> GetAccessTokenAsync()
    {
        var result = new OperationalResult<string>();

        var url = $"https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid={_weComOptions.CorpId}&corpsecret={_weComOptions.Secret}";

        var ticket = await _httpClient.GetFromJsonAsync<WeComCorpTicket>(url);

        if (ticket is null)
        {
            result.Status = OperationalResult.FAILURE;
            result.Message = "请求失败";

            return result;
        }

        result.Data = ticket.Access_token;

        _cache.Set("access_token", result.Data, TimeSpan.FromSeconds(ticket.Expires_in));

        return result;
    }

    public async Task<OperationalResult<WeComUserInfo>> GetUserInfoAsync(string code)
    {
        var accessToken = _cache.Get<string>("access_token");

        var result = new OperationalResult<WeComUserInfo>();

        if (string.IsNullOrEmpty(accessToken) || string.IsNullOrEmpty(code))
        {
            result.Status = OperationalResult.FAILURE;

            return result;
        }

        var url = $"https://qyapi.weixin.qq.com/cgi-bin/auth/getuserinfo?access_token={accessToken}&code={code}";

        var userInfo = await _httpClient.GetFromJsonAsync<WeComUserInfo>(url);

        if (userInfo is null)
        {
            result.Status = OperationalResult.FAILURE;
            result.Message = "请求失败";

            return result;
        }

        result.Data = userInfo;

        return result;
    }

    public async Task<OperationalResult<WeComPrivateUser>> SyncUserPrivateInfoAsync(string ticket, CancellationToken cancellationToken = default)
    {
        var accessToken = _cache.Get<string>("access_token");

        var result = new OperationalResult<WeComPrivateUser>();

        if (string.IsNullOrEmpty(accessToken))
        {
            result.Status = OperationalResult.FAILURE;

            return result;
        }

        var url = $"https://qyapi.weixin.qq.com/cgi-bin/auth/getuserdetail?access_token={accessToken}";

        var responseMessage = await _httpClient.PostAsJsonAsync(
            url,
            new { user_ticket = ticket },
            new JsonSerializerOptions { PropertyNamingPolicy = LowerCaseNamingPolicy.LowerCase },
            cancellationToken);

        if (!responseMessage.IsSuccessStatusCode)
        {
            result.Status = OperationalResult.FAILURE;

            return result;
        }

        var wecomResponse = await responseMessage.Content.ReadFromJsonAsync<WeComPrivateUser>(cancellationToken: cancellationToken);

        if (wecomResponse is null)
        {
            result.Status = OperationalResult.FAILURE;

            return result;
        }

        result.Data = wecomResponse;

        return result;
    }

    public async Task<OperationalResult<WeComPublicUser>> GetUserAsync(string userId)
    {
        var accessToken = _cache.Get<string>("access_token");

        var result = new OperationalResult<WeComPublicUser>();

        if (string.IsNullOrEmpty(accessToken))
        {
            result.Status = OperationalResult.FAILURE;

            return result;
        }

        var url = $"https://qyapi.weixin.qq.com/cgi-bin/user/get?access_token={accessToken}&userid={userId}";

        var user = await _httpClient.GetFromJsonAsync<WeComPublicUser>(url);

        if (user is null)
        {
            result.Status = OperationalResult.FAILURE;
            result.Message = "请求失败";

            return result;
        }

        result.Data = user;

        return result;
    }

    public async Task<ListResult<Department>> GetDepartmentsAsync()
    {
        var accessToken = _cache.Get<string>("access_token");

        var result = new ListResult<Department>();

        if (string.IsNullOrEmpty(accessToken))
        {
            accessToken = (await GetAccessTokenAsync()).Data;
        }

        var url = $"https://qyapi.weixin.qq.com/cgi-bin/department/list?access_token={accessToken}";

        var departments = await _httpClient.GetFromJsonAsync<WeComDepartments>(url);

        if (departments is null || departments.Errcode != 0)
        {
            result.Status = OperationalResult.FAILURE;
            result.Message = "获取企业微信部门数据失败";

            return result;
        }

        var depts = departments.Department.Select(n => new Department
        {
            Id = n.Id,
            Name = n.Name,
            Parent = n.ParentId != 1 ? new Department { Id = n.ParentId } : null
        });

        result.Data = depts;

        return result;
    }

    public async Task<ListResult<User>> GetDepartmentUsersAsync(Department department)
    {
        var accessToken = _cache.Get<string>("access_token");

        var result = new ListResult<User>();

        if (string.IsNullOrEmpty(accessToken))
        {
            accessToken = (await GetAccessTokenAsync()).Data;
        }

        var url = $"https://qyapi.weixin.qq.com/cgi-bin/user/list?access_token={accessToken}&department_id={department.Id}";

        var users = await _httpClient.GetFromJsonAsync<WeComDepartmentUsers>(url);

        if (users is null)
        {
            result.Status = OperationalResult.FAILURE;
            result.Message = "获取企业微信部门用户数据失败";

            return result;
        }

        var entities = users.UserList.Select(n => new User
        {
            Name = ParseName(n.Name),
            Account = ParseJobNumber(n.Name),
            JobNumber = ParseJobNumber(n.Name),
            UserId = n.UserId,
            Password = App.Encrypt("ap"),
            Department = department,
            Mobile = string.IsNullOrEmpty(n.Telephone) ? null : n.Telephone,
            IsLeader = n.IsLeader == 1,
            DirectLeader = n.Direct_leader.Length != 0 ? new User
            {
                UserId = n.Direct_leader[0]
            } : null,
        }).ToList();

        foreach (var entity in entities)
        {
            if (entity.DirectLeader is not null)
            {
                entity.DirectLeader = entities.First(x => x.UserId == entity.DirectLeader.UserId);
            }
        }

        result.Data = entities;

        return result;
    }

    public async Task<OperationalResult<WeComResponseBase>> SendTextMessageAsync(string userId, string content)
    {
        var message = new WeComTextMessage
        {
            ToUser = userId,
            AgentId = _weComOptions.AgentId,
            Text = new WeComTextMessageDetail { Content = content }
        };

        return await SendMessageAsync(message);
    }

    public async Task<OperationalResult<string>> SendButtonInteractionMessageAsync(string userId, WeComButtonTemplateCard card, string? callbackKey = null)
    {
        var result = new OperationalResult<string>();

        card.ToUser = userId;
        card.AgentId = _weComOptions.AgentId;
        card.Template_card.Task_id = Guid.NewGuid().ToString("N");

        var sendResult = await SendMessageAsync(card);

        if (sendResult.EnsureSucceed())
        {
            if (callbackKey is not null)
            {
                var job = new ScheduleJob
                {
                    JobId = card.Template_card.Task_id,
                    Key = callbackKey,
                };

                var context = App.HttpContext!.RequestServices.GetRequiredService<DbContext>();
                await context.Set<ScheduleJob>().AddAsync(job);
                await context.SaveChangesAsync();
            }

            result.Data = card.Template_card.Task_id;

            return result;
        }

        return OperationalResult<string>.Fail();
    }

    private async Task<OperationalResult<WeComResponseBase>> SendMessageAsync<TMessage>(TMessage message)
        where TMessage : WeComMessage, new()
    {
        var accessToken = _cache.Get<string>("access_token");

        var result = new OperationalResult<WeComResponseBase>();

        if (string.IsNullOrEmpty(accessToken))
        {
            accessToken = (await GetAccessTokenAsync()).Data;
        }

        var url = $"https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token={accessToken}";

        var responseMessage = await _httpClient.PostAsJsonAsync(
            url,
            message,
            new JsonSerializerOptions { PropertyNamingPolicy = LowerCaseNamingPolicy.LowerCase, Encoder = JavaScriptEncoder.Create(UnicodeRanges.All) });

        if (!responseMessage.IsSuccessStatusCode)
        {
            result.Status = OperationalResult.FAILURE;

            return result;
        }

        var wecomResponse = await responseMessage.Content.ReadFromJsonAsync<WeComResponseBase>();

        if (wecomResponse is null)
        {
            result.Status = OperationalResult.FAILURE;

            return result;
        }

        result.Data = wecomResponse;

        Console.WriteLine(wecomResponse.ErrMsg);

        return result;
    }

    public async Task UpdateSampleTemplateCardAsync(WeComTemplateCardSampleUpdate model)
    {
        var accessToken = _cache.Get<string>("access_token");


        if (string.IsNullOrEmpty(accessToken))
        {
            accessToken = (await GetAccessTokenAsync()).Data;
        }

        var url = $"https://qyapi.weixin.qq.com/cgi-bin/message/update_template_card?access_token={accessToken}";

        var responseMessage = await _httpClient.PostAsJsonAsync(
            url,
            model,
            new JsonSerializerOptions { PropertyNamingPolicy = LowerCaseNamingPolicy.LowerCase, Encoder = JavaScriptEncoder.Create(UnicodeRanges.All) });

        if (!responseMessage.IsSuccessStatusCode)
        {
            return;
        }

        var wecomResponse = await responseMessage.Content.ReadFromJsonAsync<WeComResponseBase>();

        if (wecomResponse is null)
        {
            return;
        }

        Console.WriteLine(wecomResponse.ErrMsg);
    }

    private static string ParseJobNumber(string name)
    {
        return name.Split(' ')[0];
    }

    private static string ParseName(string name)
    {
        return name.Split(' ')[1].Split('(')[0].Split('（')[0].TrimEnd();
    }    
}